package com.my.house.common.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.my.house.common.BizException;
import com.my.house.common.config.JsonConfig;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * Jackson工具类
 * @author yangll
 */
@Slf4j
public class JsonUtils {

    /**
     * 通用OM对象
     */
    private static ObjectMapper OM = null;

    public static ObjectMapper getOM() {
        if (Objects.isNull(OM)){
            synchronized (JsonUtils.class) {
                if (Objects.isNull(OM) && Objects.nonNull(SpringUtil.getBean(ObjectMapper.class))){
                    //和框架OM同源，防止json相互转换报错，或字段名不一致
                    OM = SpringUtil.getBean(ObjectMapper.class);
                    log.info("使用容器内的Bean<ObjectMapper>执行json格式化");
                }else{
                    //junit或main方法测试使用
                    log.info("使用自定义ObjectMapper执行json格式化");
                    OM = JsonConfig.getDefaultMapper();
                }
            }
        }
        return OM;
    }

    /**
     * 判断是否json字符串
     * @param json 目标json字符
     * @return true是 false否
     */
    public static boolean isJsonStr(String json) {
        if (StrUtil.isBlank(json)) {
            return false;
        }
        return json.startsWith("{") || json.startsWith("[");
    }

    /**
     * 获取打印输出字符，防止字符串过长，日志里不好看
     * @return 方便观察的字符
     */
    public static Object getPrintStr(Object obj) {
        if (obj instanceof String json) {
            if (StrUtil.isBlank(json) || json.length() < 500) {
                return json;
            }
            return json.substring(0, 500);
        }
        return obj;
    }

    /**
     * 把java对象转成json字符串
     * @param obj java对象(object map list等)
     * @return json字符串
     */
    public static String toJsonString(Object obj) throws JsonProcessingException {
        if (Objects.isNull(obj)) {
            return null;
        }
        try {
            return getOM().writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw e;
        }
    }

    /**
     * 把json字符串或对象转成java对象
     * @param obj json字符串或Map对象或其他对象等
     * @param tClass java对象类型(object map list等)
     * @return java对象
     * @param <T> class类型
     */
    public static <T> T convertBean(Object obj, Class<T> tClass) throws JsonProcessingException {
        if (Objects.isNull(obj) || Objects.isNull(tClass)) {
            return null;
        }
        try {
            if (obj instanceof String json){
                //字符串转对象
                return getOM().readValue(json, tClass);
            } else {
                //对象转对象，比如 map转对象
                return getOM().convertValue(obj, tClass);
            }
        } catch (JsonProcessingException e) {
            throw e;
        }
    }

    /**
     * json对象转为List<bean>
     * @param jsonData json对象
     * @param beanType bean类型
     * @return List<bean>
     * @param <T> bean类型
     * @throws JsonProcessingException
     */
    public static <T> List<T> json2List(Object jsonData, Class<T> beanType) throws JsonProcessingException {
        if (Objects.isNull(jsonData) || Objects.isNull(beanType)) {
            return null;
        }
        ObjectMapper mapper = getOM();
        JavaType javaType = mapper.getTypeFactory().constructParametricType(List.class, beanType);

        try {
            if (jsonData instanceof String json) {
                if (StrUtil.isBlank(json)) {
                    return CollUtil.newArrayList();
                }
                return mapper.readValue(json, javaType);
            } else {
                return mapper.readValue(toJsonString(jsonData), javaType);
            }
        } catch (JsonProcessingException e) {
            throw e;
        }
    }

    public static <K, V> Map<K, V> json2Map(Object jsonData, Class<K> keyType, Class<V> valueType) throws JsonProcessingException {
        if (Objects.isNull(jsonData)) {
            return null;
        }
        ObjectMapper mapper = getOM();
        JavaType javaType = mapper.getTypeFactory().constructMapType(Map.class, keyType, valueType);

        try {
            if (jsonData instanceof String json) {
                if (StrUtil.isBlank(json)) {
                    return MapUtil.newHashMap();
                }
                return mapper.readValue(json, javaType);
            } else {
                return mapper.readValue(toJsonString(jsonData), javaType);
            }
        } catch (JsonProcessingException e) {
            throw e;
        }
    }

    public static String easyToJsonString(Object obj) {

        try {
            return toJsonString(obj);
        } catch (JsonProcessingException e) {
            log.error("json解析异常", e);
            throw new BizException("json解析异常");
        }

    }

    public static <T> T easyConvertBean(Object obj, Class<T> tClass) {
        try {
            return convertBean(obj, tClass);
        } catch (JsonProcessingException e) {
            log.error("json解析异常", e);
            throw new BizException("json解析异常");
        }
    }

    public static <T> List<T> easyJson2List(Object jsonData, Class<T> beanType){
        try {
            return json2List(jsonData, beanType);
        } catch (JsonProcessingException e) {
            log.error("json解析异常", e);
            throw new BizException("json解析异常");
        }
    }

    public static <K, V> Map<K, V> easyJson2Map(Object jsonData, Class<K> keyType, Class<V> valueType){
        try {
            return json2Map(jsonData,keyType, valueType);
        } catch (JsonProcessingException e) {
            log.error("json解析异常", e);
            throw new BizException("json解析异常");
        }
    }

    /**
     * 读取文件里的内容，转换为Java bean
     * @param src 文件
     * @param valueTypeRef 内容类型
     * @param <T> 内容bean
     */
    public static  <T> T readFileValue(File src, TypeReference<T> valueTypeRef){
        if (Objects.isNull(src) || Objects.isNull(valueTypeRef)) {
            return null;
        }
        ObjectMapper mapper = getOM();

        try {
            return mapper.readValue(src, valueTypeRef);
        } catch (Exception e) {
            log.error("读取文件失败：{}", src.getAbsolutePath());
            return null;
        }
    }

}
